package insight.google.game.era.data;

import insight.google.game.era.bo.GameRoom;

import insight.google.game.era.bo.card.GameCard;
import insight.google.game.era.core.GameCenterManager;
import insight.google.game.era.core.ServiceCenterImpl;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Query;
import javax.jdo.Transaction;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.datanucleus.jdo.NucleusJDOHelper;

import com.google.appengine.api.datastore.DatastoreTimeoutException;
import com.google.appengine.api.datastore.Key;

public class DataStoreManager {

	/**
	 * 
	 */
	private static DataStoreManager instance = null;// new DataStoreManager();
	private static final PersistenceManagerFactory pmfInstance = JDOHelper
			.getPersistenceManagerFactory("transactions-optional");
	 private static PersistenceManager pManager = null;
	private static final Log log = LogFactory.getLog(DataStoreManager.class);

	private DataStoreManager() {
//		 pManager = pmfInstance.getPersistenceManager();
	}

	public static DataStoreManager getInstance() {
		if (instance == null) {
			instance = new DataStoreManager();
			instance.createPersisManager(null);
		}
		return instance;
	}

	// private void init(){
	// if(instance != null){
	// pManager = pmfInstance.getPersistenceManager();
	// }
	// }

	public PersistenceManager getPersistentManager() {
		return this.createPersisManager(null);
	}

	private PersistenceManager createPersisManager(Object obj) {
		// pManager = JDOHelper.getPersistenceManager(obj);
		PersistenceManager pManager = pmfInstance.getPersistenceManager();
		if (pmfInstance != null) {
//			pManager = pmfInstance.getPersistenceManager();
//			// pManager.setDetachAllOnCommit(true);
			pManager.getFetchPlan().addGroup("user_room");
//
			pManager.getFetchPlan().addGroup("room_user_list");
//			pManager.getFetchPlan().addGroup("flowManager");
			pManager.getFetchPlan().addGroup("gameLogManager");
			pManager.getFetchPlan().addGroup("game_history");
//
			pManager.getFetchPlan().setMaxFetchDepth(3);
//
		}
		return pManager;
	}

	public List get(Class obj, PersistenceManager pManager,boolean isDetachable)
			throws InterruptedException {
		log.debug("DataStore id is ---   " + this.toString());
		List results = null;
		List returnObj = null;
		// this.createPersisManager(obj);
		Query query = pManager.newQuery(obj);
		int timeout_ms = 100;
		while (true) {
			try {
				results = (List) query.execute();
				if(isDetachable){
					returnObj = (List) pManager.detachCopyAll(results); 
				}else{
					returnObj = results;
				}
//				detachObj = 
				log.debug("got object of " + obj.getName()
						+ "  result size is  " + results.size());
				break;
			} catch (DatastoreTimeoutException dse) {
				Thread.currentThread().sleep(timeout_ms);
				timeout_ms *= 2;
			} catch (Exception e) {
				log.debug("Excpetion happen for " + obj.getClass().getName()
						+ " Message ");
				log.debug(" Message ####    " + e.getMessage());
				e.printStackTrace();
			} finally {
				// query.closeAll();
				// if(!pManager.isClosed()){
				// pManager.close();
				// }
			}
		}

//		return detachObj;
		return returnObj;
	}
	
//	public List getDetached(Class obj, PersistenceManager pManager)
//			throws InterruptedException {
//		log.debug("DataStore id is ---   " + this.toString());
//		List results = null;
//		List detachObj = null;
//		Query query = pManager.newQuery(obj);
//		int timeout_ms = 100;
//		while (true) {
//			try {
//				results = (List) query.execute();
//				detachObj = (List) pManager.detachCopyAll(results);
//				log.debug("got object of " + obj.getName()
//						+ "  result size is  " + results.size());
//				break;
//			} catch (DatastoreTimeoutException dse) {
//				Thread.currentThread().sleep(timeout_ms);
//				timeout_ms *= 2;
//			} catch (Exception e) {
//				log.debug("Excpetion happen for " + obj.getClass().getName()
//						+ " Message ");
//				log.debug(" Message ####    " + e.getMessage());
//				e.printStackTrace();
//			} finally {
//				
//			}
//		}
//
//		return detachObj;
//	// return results;
//	}

	
	public Object getById(Class obj, Key id, PersistenceManager pManager,boolean isDetachable) {
		log.debug("DataStore id is ---   " + this.toString());
		Object results = null;
		Object returnObj = null;
		try {
			results = (Object) pManager.getObjectById(obj, id);
//			 detachObj = pManager.detachCopyAll(results);
			if(isDetachable){
				returnObj = pManager.detachCopyAll(results); 
			}else{
				returnObj = results;
			}
			
			if (returnObj != null && returnObj.getClass().isArray() ) {
				returnObj = ((Object[]) returnObj)[0];
			}
			log.debug("got object of " + obj.getName() + "  result is  "
					+ results.toString());
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			
		}
//		 return detachObj;
		return returnObj;
	}
	
//	public Object getDetachedObjectById(Class obj, Key id, PersistenceManager pManager) {
//		log.debug("DataStore id is ---   " + this.toString());
//		Object results = null;
//		Object detachObj = null;
//		try {
//			results = (Object) pManager.getObjectById(obj, id);
//			 detachObj = pManager.detachCopyAll(results);
//			if (detachObj != null) {
//				detachObj = ((Object[]) detachObj)[0];
//			}
//			log.debug("got object of " + obj.getName() + "  result is  "
//					+ results.toString());
//		} catch (Exception e) {
//			e.printStackTrace();
//		} finally {
//			
//		}
//		 return detachObj;
////		return results;
//	}

	public List getByCondition(Class obj, String cond,
			PersistenceManager pManager,boolean isDetachable) throws InterruptedException {
		log.debug("DataStore id is ---   " + this.toString());
		List results = null;
		List returnObj = null;

		Query query = pManager.newQuery(obj);
		query.setFilter(cond);
//		int timeout_ms = 100;
//		while (true) {
			try {
				results = (List) query.execute();
				if(isDetachable){
					returnObj = (List) pManager.detachCopyAll(results); 
				}else{
					returnObj = results;
				}
//				 detachObj = (List)pManager.detachCopyAll(results);
				log.debug("got object of " + obj.getName()
						+ "  result size is  " + results.size());
//				break;
			} catch (DatastoreTimeoutException dse) {
				dse.printStackTrace();
//				Thread.currentThread().sleep(timeout_ms);
//				timeout_ms *= 2;
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
			}
//		}
//		return detachObj;
		 return returnObj;
	}
//	public List getDetachedObjectByCondition(Class obj, String cond,
//			PersistenceManager pManager) throws InterruptedException {
//		log.debug("DataStore id is ---   " + this.toString());
//		List results = null;
//		List detachObj = null;
//
//		Query query = pManager.newQuery(obj);
//		query.setFilter(cond);
//		int timeout_ms = 100;
//		while (true) {
//			try {
//				results = (List) query.execute();
//				 detachObj = (List)pManager.detachCopyAll(results);
//				log.debug("got object of " + obj.getName()
//						+ "  result size is  " + results.size());
//				break;
//			} catch (DatastoreTimeoutException dse) {
//				Thread.currentThread().sleep(timeout_ms);
//				timeout_ms *= 2;
//			} catch (Exception e) {
//				e.printStackTrace();
//			} finally {
//			}
//		}
//		return detachObj;
////		 return results;
//	}

	public List getByConditionWithKeyParam(Class obj, String cond,
			PersistenceManager pManager, Key refKey,boolean isDetachable)
			throws InterruptedException {
		log.debug("DataStore id is ---   " + this.toString());
		List results = null;
		List returnObj = null;

		Query query = pManager.newQuery(obj);
		query.setFilter(cond);
		int timeout_ms = 100;
		while (true) {
			try {
				if (refKey != null) {
					results = (List) query.execute(refKey);
				} else {
					results = (List) query.execute();
				}
				if(isDetachable){
					returnObj = (List) pManager.detachCopyAll(results); 
				}else{
					returnObj = results;
				}
//				 detachObj = (List)pManager.detachCopyAll(results);
				log.debug("got object of " + obj.getName()
						+ "  result size is  " + results.size());
				break;
			} catch (DatastoreTimeoutException dse) {
				Thread.currentThread().sleep(timeout_ms);
				timeout_ms *= 2;
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
			}
		}
		return returnObj;
//		return results;
	}

	public List getByConditionNOrder(Class obj, String cond,
			PersistenceManager pManager, String orderBy, Key refKey,boolean isDetachable)
			throws InterruptedException {
		log.debug("DataStore id is ---   " + this.toString());
		List results = null;
		List returnObj = null;

		Query query = pManager.newQuery(obj);
		query.setFilter(cond);
		query.setOrdering(orderBy);
		int timeout_ms = 100;
		while (true) {
			try {
				if (refKey != null) {
					results = (List) query.execute(refKey);
				} else {
					results = (List) query.execute();
				}
				if(isDetachable){
					returnObj = (List) pManager.detachCopyAll(results); 
				}else{
					returnObj = results;
				}
//				detachObj = results;
//				 detachObj = (List)pManager.detachCopyAll(results);
				log.debug("got object of " + obj.getName()
						+ "  result size is  " + results.size());
				break;
			} catch (DatastoreTimeoutException dse) {
				Thread.currentThread().sleep(timeout_ms);
				timeout_ms *= 2;
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
			}
		}
		return returnObj;
//		 return results;
	}

	public Object save(Object obj, PersistenceManager pManager,boolean isDetachable)
			throws InterruptedException {
		log.debug("DataStore id is ---   " + this.toString());
		Object result = null;
		Object returnObj = null;
		int timeout_ms = 100;
		
		while (true) {
			try {
				log.debug("saving object of " + obj.getClass().getName());
				result = pManager.makePersistent(obj);
				if(isDetachable){
					returnObj = pManager.detachCopyAll(result); 
				}else{
					returnObj = result;
				}
				log.debug("got object of " + obj.getClass().getName()
						+ "  result size is  " + result.toString());
				break;
			} catch (DatastoreTimeoutException dse) {
				Thread.currentThread().sleep(timeout_ms);
				timeout_ms *= 2;
			} catch (Exception e) {
				log.debug("Excpetion happen for " + obj.getClass().getName()
						+ " Message ");
				log.debug(" Message ####    " + e.getMessage());
				e.printStackTrace();
			} finally {
			}
		}
//		 return detachObj;
		return returnObj;
	}

	public Object saveAll(Collection obj, PersistenceManager pManager) {
		log.debug("DataStore id is ---   " + this.toString());
		// this.createPersisManager(obj);
		// Transaction tx = pManager.currentTransaction();
		// pManager.setDetachAllOnCommit(true);
		Object result = null;
		try {
			// tx.begin();
			result = pManager.makePersistentAll(obj);
			// tx.commit();

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// if (tx.isActive()) {
			// tx.rollback();
			// }
			// if(!pManager.isClosed()) pManager.close();
		}
		return result;
	}

	// public void atachObject(Object obj){
	// Transaction tx = pManager.currentTransaction();
	// try {
	// tx.begin();
	// pManager.set
	// pManager.a (results.get(0));
	//	        
	//	        
	// tx.commit();
	// }
	// finally {
	// query.closeAll();
	// if (tx.isActive()) {
	// tx.rollback();
	// }
	// }
	// }

	public Object getDettachByCondition(Class obj, List<String> cond,
			PersistenceManager pManager) {
		List results = null;
		Object detachObj = null;
		Query query = pManager.newQuery(obj);
		for (int i = 0; i < cond.size(); i++) {
			query.setFilter(cond.get(i));
		}
		// Transaction tx = pManager.currentTransaction();
		try {
			// tx.begin();
			results = (List) query.execute();
			if (results != null || results.size() > 0) {
				detachObj = pManager.detachCopy(results.get(0));
			}
			// tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			query.closeAll();
			// if (tx.isActive()) {
			// tx.rollback();
			// }
		}
		return detachObj;
	}

	public Object updateDettached(Object obj, PersistenceManager pManager) {

		Object result = null;
		try {
			result = pManager.makePersistent(obj);

		} finally {

		}
		return result;
	}

	public boolean delete(Object obj, PersistenceManager pManager) {
//		this.createPersisManager(obj);
		// Transaction tx = pManager.currentTransaction();
		log.debug("Deleting   ..   " + obj.toString() );
		
		Object result = null;
		try {
			// tx.begin();
			pManager.deletePersistent(obj);
			// tx.commit();

		} catch (Exception e) {
			log.debug("Excpetion happen for " + obj.getClass().getName()
					+ " Message ");
			log.debug(" Message ####    " + e.getMessage());
			e.printStackTrace();
		} finally {
			// if (tx.isActive()) {
			// tx.rollback();
			// }
		}
		return true;
	}

	public void deleteAll(List dataList, PersistenceManager pManager) {
		
		Object result = null;
		try {
			pManager.deletePersistentAll(dataList);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
		}
	}

	// public void updatebyId(Object obj){
	// Transaction tx = pManager.currentTransaction();
	// Object result = null;
	// try {
	// tx.begin();
	// Object targetObj = pManager.getObjectById(obj);
	// target
	// result = pManager.makePersistent(obj);
	// tx.commit();
	// } finally {
	// if (tx.isActive()) {
	// tx.rollback();
	// }
	// }
	// return result;
	//		
	//		
	// PersistenceManager pm = PMF.get().getPersistenceManager();
	// try {
	// Employee e = pm.getObjectById(Employee.class, user.getEmail());
	// if (titleChangeIsAuthorized(e, newTitle) {
	// e.setTitle(newTitle);
	// } else {
	// throw new UnauthorizedTitleChangeException(e, newTitle);
	// }
	// } finally {
	// pm.close();
	// }
	// }

}
